package com.study.kt._03coroutines

import kotlinx.coroutines.CoroutineStart
import kotlinx.coroutines.async
import kotlinx.coroutines.delay
import kotlinx.coroutines.runBlocking
import kotlin.system.measureTimeMillis

/* async+await实现高效并行

* async：像launch一行，他会开启独立的协程，这个协程是是个轻量级线程，可以与其他协程并发工作，
*       区别：launch方法返回一个Job，但是Job不会持有任何结果值，而async返回一个Deferred,这是一个轻量级的非阻塞的future，
*       它代表一个promise，可以在稍后提供一个结果值
*   Deferred通过调用await方法获取最终结果值，Deferred也是Job，因此可以对其取消
* */
fun main() = runBlocking {
    //syncLaunch() // 1.同步运行
    asyncLaunch() // 2.高效并行
    //lazyLaunch() //3.通过async延迟执行
}

// 延迟执行（默认情况下协程直接执行，使用CoroutineStart改变执行逻辑）
fun lazyLaunch() = runBlocking {
    val elapsedTime = measureTimeMillis {
        // 通过CoroutineStart.LAZY指定为延迟执行
        // 要运行延迟加载的async 此时协程会在两种情景执行：调用Job.start、Deferred.await
        val value1 = async(start = CoroutineStart.LAZY) {
            println("value1")
            intValue1()
        }
        val value2 = async(start = CoroutineStart.LAZY) {
            println("value2")
            intValue2()
        }
        println("hello")
        Thread.sleep(3000)
        // start方法为非阻塞,此时程序执行5000+
        // 如果此处不使用start方法，则执行6000+
        //value1.start()
        //value2.start()

        // 如果没有start方法Lazy模式下协程不会立即执行，调用await才执行
        // value1.await()耗时1s才执行value2.await()所以时间为3000+1000+2000
        val num1 = value1.await()
        val num2 = value2.await()
        //        println("result=${num1 + num2}")
    }
    println("方法耗时：${elapsedTime}")
}

// 并发 方法耗时2000+
private fun asyncLaunch() = runBlocking {
    val elapsedTime = measureTimeMillis {
        val value1 = async { intValue1() }
        val value2 = async { intValue2() }
        val v = value1.await()
        val v2 = value2.await()
        println("${v},${v2}")
    }
    println("方法耗时：${elapsedTime}")
}

// 传统串行
/*
*  该方法运行耗时3000+毫秒，因为在intValue1()运行时，intValue2()方法被阻塞
*   理想的做法是在intValue1()运行时intValue2()也要运行，等两者运行结束再共同输出
*   使用 async、await就可以解决
* */
private fun syncLaunch() = runBlocking {
    val elapsedTime = measureTimeMillis {
        val value1 = intValue1()
        val value2 = intValue2()
        println("result=${value1 + value2}")
    }
    println("方法耗时：${elapsedTime}")
}

private suspend fun intValue1(): Int {
    delay(1000)
    return 1
}
private suspend fun intValue2(): Int {
    delay(4000)
    return 2
}